#pragma once

#include "ThreadCache.hpp"
#include "PageCache.hpp"
#include "CorrectionIndex.hpp"
#include "FixSizeConcurrentMemoryPool.hpp"

using namespace ThreadCacheModule;
using namespace PageCacheModule;
using namespace CorrectionIndexModule;
using namespace FixSizeMemoryPoolModule;

struct TCMalloc
{
    //提供给外层的获取内存池的接口，保证每个线程都有
    static void* Malloc(size_t size)
    {
        //我们的Page Cache的大小是128*8K，因此这里我们的内存申请可以分成三个部分：
        //                                              0~32页（0~256KB）  33~128页（256KB + 1~1024KB） 大于128页（1024KB+1）
        //对应的申请内存的方式：   逐层申请                        向PageCache申请                            向堆申请（在Page Cache中进行）
        if (size > MAXMEMORYSIZE)
        {
            // 算出对齐数
            size_t align_num = CorrectionIndex::AlignedNum(size);
            //算出所需的页数
            size_t page_num = CorrectionIndex::PageNum(align_num);
            //直接从page cache中申请
            PageCache::GetInstance()->GetMutex().lock();
            Span* span=PageCache::GetInstance()->GetSpan(page_num);
            span->_size = size;
            PageCache::GetInstance()->GetMutex().unlock();

            return (void*)(span->_id << PAGESIZESHIFT);
        }
        else
        {
            // 通过TLS 每个线程无锁的获取自己的专属的ThreadCache对象
            if (pTLSThreadCache == nullptr)
            {
                static FixSizeMemoryPool< ThreadCache> tcPool;
                //pTLSThreadCache = new ThreadCache;
                pTLSThreadCache = tcPool.New();
            }

            return pTLSThreadCache->Allocate(size);
        }

    }
    static void Free(void* ptr)
    {
        //地址获得span，span得到size
        Span* span = PageCache::GetInstance()->IdToSpan(ptr);
        size_t size = span->_size;
        if (size > MAXMEMORYSIZE)
        {
            PageCache::GetInstance()->GetMutex().lock();
            PageCache::GetInstance()->ReleaseSpanToPageCache(span);
            PageCache::GetInstance()->GetMutex().unlock();
        }
        else
        {
            assert(pTLSThreadCache);
            pTLSThreadCache->Deallocate(ptr, size);
        }
    }
};